package org.spring.bean.factory.support;

import com.sun.istack.internal.Nullable;
import org.spring.bean.exceptions.BeansException;
import org.spring.bean.factory.BeanFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * 负责创建对应于根 bean 定义的实例的接口。
 * <p>
 * 由于可以采用各种方法，包括使用 CGLIB 动态创建子类以支持方法注入，因此这被引入了一种策略。
 * <p>
 * 注：根据 RootBeanDefinition 对象生成对应的 bean 对象
 *
 * @author 李坤
 * @date 2022/4/21 16:03
 */
public interface InstantiationStrategy {

    /**
     * 在此工厂中返回具有给定名称的 bean 实例。
     *
     * @param beanDefinition bean 定义
     * @param beanName       在此上下文中创建 bean 时的名称。如果我们要自动装配不属于工厂的 bean，则名称可以是 {@code null}。
     * @param beanFactory    拥有的 BeanFactory
     *
     * @return 此 bean 定义的 bean 实例
     *
     * @throws BeansException 如果实例化尝试失败
     */
    Object instantiate(RootBeanDefinition beanDefinition, @Nullable String beanName, BeanFactory beanFactory) throws BeansException;

    /**
     * 在此工厂中返回具有给定名称的 bean 实例，并通过给定的构造函数创建它。
     *
     * @param beanDefinition bean 定义
     * @param beanName       在此上下文中创建 bean 时的名称。如果我们要自动装配不属于工厂的 bean，则名称可以是 {@code null}。
     * @param beanFactory    拥有的 BeanFactory
     * @param constructor    要使用的构造函数
     * @param args           要应用的构造函数参数
     *
     * @return 此 bean 定义的 bean 实例
     *
     * @throws BeansException 如果实例化尝试失败
     */
    Object instantiate(RootBeanDefinition beanDefinition, @Nullable String beanName, BeanFactory beanFactory,
                       Constructor<?> constructor, Object... args) throws BeansException;

    /**
     * 返回此工厂中具有给定名称的 bean 实例，通过给定的工厂方法创建它。
     *
     * @param beanDefinition bean 定义
     * @param beanName       在此上下文中创建 bean 时的名称。如果我们要自动装配不属于工厂的 bean，则名称可以是 {@code null}。
     * @param beanFactory    拥有的 BeanFactory
     * @param factoryBean    调用工厂方法的工厂 bean 实例，如果是静态工厂方法，则为 {@code null}
     * @param factoryMethod  使用的工厂方法
     * @param args           要应用的工厂方法参数
     *
     * @return 此 bean 定义的 bean 实例
     *
     * @throws BeansException 如果实例化尝试失败
     */
    Object instantiate(RootBeanDefinition beanDefinition, @Nullable String beanName, BeanFactory beanFactory,
                       @Nullable Object factoryBean, Method factoryMethod, Object... args) throws BeansException;

}
